package org.apache.xml.dtm.ref;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;
import org.xml.sax.XMLReader;
import java.io.IOException;

/** Primitive unit test for CoroutineSAXParser in filtering mode:
 * Attempt coroutine parsing of documents indicated by arguments (as
 * URIs), report progress. If a URI is followed by "!" as the next
 * argument, we cancel the parse early.
 *
 * This version tests the filtering mode, where the CoroutineParser
 * is managing a SAX stream generated by other code. Normally this
 * would be used when you've launched the consumer in a secondary
 * thread and are running the SAX event generation in the primary
 * thread. Of course it could be used the other way round as well.
 *
 * Note that unlike the fully-encapsulated version (see the inline
 * test in CoroutineSAXParser), this version does _not_ have a
 * dialog for starting the parse, or for restarting it with a new
 * file.
 * */
class CoroutineSAXFilterTest implements Runnable
{
  // Statics are a sloppy way of passing data to the test thread,
  // but for this quick-hack I don't much care.
  static boolean TEST_EARLY_STOP=false;
  static int appCoroutineID=-1;
  static CoroutineSAXParser filter;

  public static void main(String args[])
  {
    System.out.println("Starting in Filtering mode...");

    org.xml.sax.XMLReader theSAXParser=
      new org.apache.xerces.parsers.SAXParser();
    
    CoroutineManager co = new CoroutineManager();

    appCoroutineID = co.co_joinCoroutineSet(appCoroutineID);
    if (appCoroutineID == -1)
      {
        System.out.println("ERROR: Couldn't allocate coroutine number.\n");
        return;
      }

    // Note that this is a global -- sloppy connection to the thread.
    filter=new CoroutineSAXParser(co, appCoroutineID);

    // Convenience function... Set handlers
    filter.setXMLReader(theSAXParser);
    
    // Use a serializer as our sample output
    org.apache.xml.serialize.XMLSerializer trace;
    trace=new org.apache.xml.serialize.XMLSerializer(System.out,null);
    filter.setContentHandler(trace);
    filter.setLexHandler(trace);

    // Launch the listener.
    Thread listener=new Thread(new CoroutineSAXFilterTest());
    listener.setDaemon(false);
    listener.start();
    
    // Check stop-early flag
    if(args.length>1 && "!".equals(args[1]))
      TEST_EARLY_STOP=true;

    // Run the parser
    System.out.println("*** Parser start ***");
    try
      {
        theSAXParser.parse(new InputSource(args[0]));
      }
    catch(java.io.IOException e)
      {
        e.printStackTrace();
      }
    catch(org.xml.sax.SAXException e)
      {
        e.printStackTrace();

        // %REVIEW% We'll should probably expose these special types,
        // if we might be testing them outside the filtering code...

        Exception embedded=e.getException();
        if(embedded!=null && embedded.getClass().getName().equals("org.apache.xml.dtm.CoroutineSAXParser$UserRequestedStopException"))
          System.out.println("... NORMAL response to doTerminate().");
      }
    System.out.println("*** Parser end ***");
    filter.doTerminate(appCoroutineID);
  }
  
  // Issue coroutine transactions to simulate dialog with the parser
  // for a single file.  Note that the sequence of calls here is
  // identical to that when talking to the fully encapsulated
  // parser... though doParse() will be a no-op since the parse
  // is launched separately.
  public void run() {
  {
    // %TBD% PROBLEM: Parser error hangs this process...

    Object result;
    boolean more=true;

    for(result = filter.doParse(null, appCoroutineID);
        (result instanceof Boolean && ((Boolean)result)==Boolean.TRUE);
        result = filter.doMore(more, appCoroutineID))
      {
        // Special test: Terminate parsing early.
        if(TEST_EARLY_STOP)
          {
            System.out.println("\nSome parsing successful, trying to stop.\n");
            more=false;
          }
        else
          System.out.println("\nSome parsing successful, trying more.\n");
      }
    
    if (result instanceof Boolean && ((Boolean)result)==Boolean.FALSE)
      {
        System.out.println("\nfilter ended (EOF or on request).\n");
      }
    else if (result == null) {
      System.out.println("\nUNEXPECTED: filter says shut down prematurely.\n");
    }
    else if (result instanceof Exception) {
      System.out.println("\nfilter threw exception:");
      ((Exception)result).printStackTrace();
    }
    
  }
  
  filter.doTerminate(appCoroutineID);
  }
  
}
